/**
 * Alibaba.com.cn Inc.
 * Copyright (c) 2004-2021 All Rights Reserved.
 */
package com.starlink.common.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SimplePropertyPreFilter;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

/**
 * @author zhanghong
 */
@Aspect
@Component
public class LogAspect {

    private final static Logger LOG = LoggerFactory.getLogger(LogAspect.class);

    @Pointcut("execution(* com.starlink..*Controller.*(..))")
    public void controllerPointcut() {}

    @Before("controllerPointcut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {

        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();

        // 打印前端请求信息
        //LOG.info("=== 开始 ===");
        //LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
        //LOG.info("类名方法: {}.{}", signature.getDeclaringTypeName(), name);
        //LOG.info("远程地址: {}", request.getRemoteAddr());

        // 打印请求参数
        Object[] args = joinPoint.getArgs();

        Object[] arguments  = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof ServletRequest
                    || args[i] instanceof ServletResponse
                    || args[i] instanceof MultipartFile) {
                continue;
            }
            arguments[i] = args[i];
        }

        // 当某些字段太敏感，或者是太长时，就不显示
        String[] excludeProperties = {};//{"password", "file"};
        SimplePropertyPreFilter filters = new SimplePropertyPreFilter();
        for (String str : excludeProperties){
            filters.getExcludes().add(str);
        }
        LOG.info("请求的参数: {}", JSON.toJSONString(arguments, filters));
    }

    @Around("controllerPointcut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();

        // 当某些字段太敏感，或者是太长时，就不显示
        String[] excludeProperties = {};//{"password", "file"};
        SimplePropertyPreFilter filters = new SimplePropertyPreFilter();
        for (String str : excludeProperties){
            filters.getExcludes().add(str);
        }
        //LOG.info("返回的结果: {}", JSON.toJSONString(result, filters));
        //LOG.info("=== 结束时，总耗时：{} s ===", (System.currentTimeMillis() - startTime)/1000);
        return result;
    }

    /**
     * 使用 Nginx 进行反向代理，这个方法主要是用来获取远程 IP
     * @param request
     * @return
     */
    public String getRemoteIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

